//
//  UIScrollView+x.m
//  XPhoto
//
//  Created by sentinel on 2020/3/26.
//  Copyright © 2020 baboy. All rights reserved.
//

#import "UIScrollView+x.h"
#import <objc/runtime.h>
#import "BKObserveDeallocObject.h"
#import "BKDragLoadingView.h"


@interface UIScrollView(_BKKit_Refresh)
@property (nonatomic, strong) BKDragLoadingView *refreshingView;
@end
@implementation UIScrollView(_BKKit_Refresh)

- (BKDragLoadingView *)refreshingView{
    return (BKDragLoadingView *)objc_getAssociatedObject(self, @selector(refreshingView));
}

- (void)setRefreshingView:(BKDragLoadingView *)refreshingView {
    objc_setAssociatedObject(self, @selector(refreshingView), refreshingView, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}

- (UIEdgeInsets)originContentInset {
    return [objc_getAssociatedObject(self, _cmd) UIEdgeInsetsValue];
}

- (void)setOriginContentInset:(UIEdgeInsets)originContentInset{
    objc_setAssociatedObject(self, @selector(originContentInset), [NSValue valueWithUIEdgeInsets:originContentInset], OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}

@end
@implementation UIScrollView(BKKit_Refresh)

- (BOOL)refresh {
    return [objc_getAssociatedObject(self, _cmd) boolValue];
}

- (void)setRefresh:(BOOL)refresh{
    objc_setAssociatedObject(self, @selector(refresh), @(refresh), OBJC_ASSOCIATION_ASSIGN);
    
    @synchronized (self) {
        BKDragLoadingView *refreshingView = self.refreshingView;
        if (refresh && !refreshingView) {
            CGRect frame = self.bounds;
            frame.origin.y = -frame.size.height;
            refreshingView = [[BKDragLoadingView alloc] initWithFrame:frame loadingType:BKDragLoadingViewTypeRefresh];
            [self addSubview:refreshingView];
            self.refreshingView = refreshingView;
            refreshingView.layer.borderColor = [UIColor brownColor].CGColor;
            refreshingView.layer.borderWidth = 10;
        }
        if (refreshingView) {
            refreshingView.hidden = !refresh;
        }
    }
}

- (void)startRefreshing{
    @synchronized (self) {
        if (!self.refresh || self.refreshingView.state == BKDragLoadingViewStateLoading) {
            return;
        }
        self.refreshingView.state = BKDragLoadingViewStateLoading;
        //    [self.layer removeAllAnimations];

        UIEdgeInsets contentInset = self.contentInset;
        contentInset.top += [self.refreshingView visibleHeight];
        self.contentInset = contentInset;
        
        if (self.delegate && [self.delegate respondsToSelector:@selector(scrollViewWillBeginRefreshing:)]) {
            [(id<BKScrollViewDragRefreshDelegate>)self.delegate scrollViewWillBeginRefreshing:self];
        }
    }
    
    
}
- (void)stopRefreshing{
    //[self.layer removeAllAnimations];
    @synchronized (self) {
        if (!self.refresh || self.refreshingView.state != BKDragLoadingViewStateLoading) {
            return;
        }
        DLOG(@"%@",NSStringFromUIEdgeInsets(self.contentInset));
        [UIView animateWithDuration:0.2
                         animations:^{
            UIEdgeInsets contentInset = self.contentInset;
            contentInset.top -= [self.refreshingView visibleHeight];
            self.contentInset = contentInset;
            
        }];
        self.refreshingView.state = BKDragLoadingViewStateLoadFinished;
    }
}
- (BOOL)shouldRefresh{
    if (!self.refresh || self.refreshingView.state == BKDragLoadingViewStateLoading) {
        return NO;
    }
    
    CGFloat scrollVisibleHeight =  -self.contentOffset.y - self.contentInset.top - self.safeAreaInsets.top;
    BOOL flag = scrollVisibleHeight > [self.refreshingView visibleHeight];
    return flag;
}
@end




@interface UIScrollView(_BKKit_LoadMore)
@property (readwrite, nonatomic, strong) BKDragLoadingView *loadingMoreView;
@end
@implementation UIScrollView(_BKKit_LoadMore)

- (BKDragLoadingView *)loadingMoreView{
    return (BKDragLoadingView *)objc_getAssociatedObject(self, @selector(loadingMoreView));
}

- (void)setLoadingMoreView:(BKDragLoadingView *)loadingMoreView {
    objc_setAssociatedObject(self, @selector(loadingMoreView), loadingMoreView, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}


@end
@implementation UIScrollView(BKKit_LoadMore)

- (void)addObserver{
    static const NSString *bkDeallocObject = nil;
    BKObserveDeallocObject *deallocObject = objc_getAssociatedObject(self, &bkDeallocObject);
    if (!deallocObject) {
        WEAK(weakSelf, self);
        deallocObject = [BKObserveDeallocObject objectWithDeallocBlock:^{
            [weakSelf removeObserver:deallocObject forKeyPath:@"contentSize"];
            [weakSelf removeObserver:deallocObject forKeyPath:@"contentOffset"];
        }];
        deallocObject.delegateObserveBlock = ^(NSString *keyPath, NSObject *object, NSDictionary *change, void * context){
            if (object == weakSelf && [keyPath isEqualToString:@"contentSize"]) {
                [weakSelf contentSizeChanged];
            }
            if (object == weakSelf && [keyPath isEqualToString:@"contentOffset"]) {
                [weakSelf contentOffsetChanged];
            }
        };
        [self addObserver:deallocObject forKeyPath:@"contentSize" options:NSKeyValueObservingOptionOld | NSKeyValueObservingOptionNew  context:nil];
//        [self addObserver:deallocObject forKeyPath:@"contentOffset" options:NSKeyValueObservingOptionOld | NSKeyValueObservingOptionNew  context:nil];
        objc_setAssociatedObject(self, &bkDeallocObject, deallocObject, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
    }
}


- (void)contentSizeChanged{
    if (self.loadMore) {
        CGRect frame = self.bounds;
        frame.origin.y = MAX(frame.size.height, self.contentSize.height);
        [self.loadingMoreView setFrame:frame];
//        self.contentInset = UIEdgeInsetsZero;
    }
    if(self.refresh){
        
    }
}

- (void)contentOffsetChanged{
    if (self.loadMore && [self shouldLoadMore]) {
        [self startLoading];
    }
}

- (BOOL)loadMore {
    return [objc_getAssociatedObject(self, _cmd) boolValue];
}

- (void)setLoadMore:(BOOL)loadMore {
    objc_setAssociatedObject(self, @selector(loadMore), @(loadMore), OBJC_ASSOCIATION_ASSIGN);
    
    @synchronized (self) {
        BKDragLoadingView *loadingMoreView = self.loadingMoreView;
        CGRect loadingMoreViewFrame = self.bounds;
        loadingMoreViewFrame.origin.y = MAX(loadingMoreViewFrame.size.height, self.contentSize.height);
        
        if (loadMore && !loadingMoreView) {
            loadingMoreView = [[BKDragLoadingView alloc] initWithFrame:loadingMoreViewFrame loadingType:BKDragLoadingViewTypeLoadMore];
            [self addSubview:loadingMoreView];
            loadingMoreView.backgroundColor = [UIColor brownColor];
            self.loadingMoreView = loadingMoreView;
            [self addObserver];
        }
        if (loadingMoreView) {
            loadingMoreView.frame = loadingMoreViewFrame;
            loadingMoreView.hidden = !loadMore;
        }
    }
}
- (void)startLoading{
    @synchronized (self) {
        if (!self.loadMore || self.loadingMoreView.state == BKDragLoadingViewStateLoading) {
            return;
        }
        self.loadingMoreView.state = BKDragLoadingViewStateLoading;

        //    [self.layer removeAllAnimations];
        [UIView animateWithDuration:0.2
                         animations:^{
            UIEdgeInsets contentInset = self.contentInset;
            contentInset.bottom += [self.loadingMoreView visibleHeight];
            self.contentInset = contentInset;
        }
                         completion:^(BOOL finished) {
            if (self.delegate && [self.delegate respondsToSelector:@selector(scrollViewWillBeginLoadingMore:)]) {
                [(id<BKScrollViewDragRefreshDelegate>)self.delegate scrollViewWillBeginLoadingMore:self];
            }
        }];
    }
    
    
}
- (void)stopLoading{
    //[self.layer removeAllAnimations];
    @synchronized (self) {
        if (!self.loadMore || self.loadingMoreView.state != BKDragLoadingViewStateLoading) {
            return;
        }
//        [UIView animateWithDuration:0.5
//                         animations:^{
//                             self.contentInset = UIEdgeInsetsZero;
//                         }];

        UIEdgeInsets contentInset = self.contentInset;
        contentInset.bottom -= [self.loadingMoreView visibleHeight];
        self.contentInset = contentInset;
        self.loadingMoreView.state = BKDragLoadingViewStateLoadFinished;
    }
}
- (BOOL)shouldLoadMore{
    DLOG(@"%d,%ld", self.loadMore, self.loadingMoreView.state);
    if (!self.loadMore || self.loadingMoreView.state == BKDragLoadingViewStateLoading) {
        return NO;
    }
    CGFloat scrollVisibleHeight =  ( self.contentOffset.y + self.bounds.size.height +self.contentInset.top ) - MAX(self.contentSize.height, self.bounds.size.height);
    BOOL flag = scrollVisibleHeight > [self.loadingMoreView visibleHeight];
    return flag;
}

//
-(void)scrollViewDidScroll{
    if (self.loadingMoreView.state == BKDragLoadingViewStateLoading) {
        return;
    }
    DLOG(@"contentOffset:%@,safeAreaInsets:%@",NSStringFromCGPoint(self.contentOffset),NSStringFromUIEdgeInsets(self.safeAreaInsets));
    if (self.loadMore) {
        CGFloat scrollVisibleHeight =  ( self.contentOffset.y + self.bounds.size.height  +self.contentInset.top) - MAX(self.contentSize.height, self.bounds.size.height);
        if (scrollVisibleHeight < [self.loadingMoreView visibleHeight]) {
            self.loadingMoreView.state = BKDragLoadingViewStateDraging;
        }else{
            self.loadingMoreView.state = BKDragLoadingViewStateDragBeyond;
        }
    }
    if (self.refresh && self.contentOffset.y < 0) {
        CGFloat thresholdOffsetY = [self.refreshingView visibleHeight] - self.contentInset.top;
        CGFloat scrollVisibleHeight = -self.contentOffset.y + self.contentInset.top - self.safeAreaInsets.top;
        if ( scrollVisibleHeight < thresholdOffsetY) {
            self.refreshingView.state = BKDragLoadingViewStateDraging;
        }else{
            self.refreshingView.state = BKDragLoadingViewStateDragBeyond;
        }
    }
    
}
-(void)scrollViewDidEndDragging{
    if ([self shouldLoadMore]) {
        [self startLoading];
    }
    if ([self shouldRefresh]) {
        [self startRefreshing];
    }
}
@end
